/**
 * @file: 通过一个具体的实例，学习如何使用C去实现面向对象的“多态”
 * 
 * 具体使用场景：我有一个公共的计算面积接口，但是我面对不同的图形，计算的方式不一样，如果是正方形那么就是边长 * 边长，如果是长方形就是长*宽，如果是圆形那么就是Π*r*r
 * 但是如何通过一个公共的接口去具体实现不同的计算方式呢？
 */
#include <stdio.h>
#include <stdlib.h>

 // 长方形的参数，两个边长
 struct rectangle_info{
	int x,y;
 };

 // 圆形的参数，半径长度和Π系数
 struct circle_info {
	float coefficient;
	int r;
 };

 typedef enum {
	SHAPE_RECTANGLE,
	SHAPE_CIRCLE
 }SHAPE_TYPE;

// 公共的基类，理解为父类
typedef struct {
	SHAPE_TYPE type;
	double (*calculate_the_area)(void*);
}shape_father;


// 圆形
typedef struct {
	shape_father base;
	struct circle_info info;
}circle_child;


// 长方形
typedef struct {
	shape_father base;
	struct rectangle_info info;
}rectangle_child;


// 圆形的面积具体实现
double circle_area(void* shape) {
	circle_child* c_chiled = (circle_child *)shape;
	return c_chiled->info.coefficient * c_chiled->info.r *c_chiled->info.r;
}

// 长方形的面积具体实现
double rectangle_area(void *shape) {
	rectangle_child * r_child = (rectangle_child *) shape;
	return r_child->info.x * r_child->info.y;
}

// 创建圆形
circle_child* createcircle(float co, int R) {
	circle_child* circle = malloc(sizeof(circle_child));
	circle->base.type = SHAPE_CIRCLE;
	circle->base.calculate_the_area = circle_area;
	circle->info.coefficient = co;
	circle->info.r = R;

	return circle;
}

// 创建长方形
rectangle_child * createrectangle(int x,int y) {
	rectangle_child * rectangle = malloc(sizeof(rectangle_child));

	rectangle->base.type = SHAPE_RECTANGLE;
	rectangle->base.calculate_the_area = rectangle_area;
	rectangle->info.x = x;
	rectangle->info.y = y;

	return rectangle;
}

double calculateArea(shape_father* shape) {
    return shape->calculate_the_area(shape);
}

int getshapetype(shape_father* shape) {
	return shape->type;
}


int main()
{
	shape_father* shape[2];
	shape[0] = (shape_father *)createcircle(3.14,3);
	shape[1] = (shape_father *)createrectangle(3,4);

	for(int i = 0; i< 2;i++){
		if(getshapetype(shape[i]) == 0) {
			printf("the rectangle");
		} else {
			printf("the circle");
		}
		printf("area is :%f\r\n",calculateArea(shape[i]));
	}

	for(int i = 0;i < 2;i++) {
		free(shape[i]);
	}

	return 0;
}
